# Copyright (c) 2024 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache Software License 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
# which is available at https://opensource.org/licenses/MIT.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT

cmake_minimum_required(VERSION 3.22)
project(iceoryx2-c VERSION ${IOX2_VERSION_STRING} LANGUAGES C)

set(PREFIX iceoryx2/v${CMAKE_PROJECT_VERSION})

#
########## Rust target ##########
#

set(USE_CARGO FALSE)
if("${RUST_BUILD_ARTIFACT_PATH}" STREQUAL "")
    set(USE_CARGO TRUE)
endif()

if(${USE_CARGO})
    message(WARNING "\
#############################################################
Using cargo to build the Rust part of iceoryx2.
This is fine for development but for production, it is
recommended to use an existing installation with
'-DRUST_BUILD_ARTIFACT_PATH=/full/path/to/iceoryx2/target/release'!
#############################################################
")

    set(RUST_BUILD_TYPE "release")
    set(RUST_BUILD_TYPE_FLAG "--${RUST_BUILD_TYPE}")
    if (CMAKE_BUILD_TYPE STREQUAL "Debug")
        set(RUST_BUILD_TYPE "debug")
        set(RUST_BUILD_TYPE_FLAG "")
    endif()

    if("${RUST_TARGET_TRIPLET}" STREQUAL "")
        set(RUST_TARGET_DIR ${CMAKE_BINARY_DIR}/rust/native)
        set(RUST_BUILD_ARTIFACT_PATH ${CMAKE_BINARY_DIR}/rust/native/${RUST_BUILD_TYPE})
        set(RUST_TARGET_TRIPLET_FLAG "")
    else()
        set(RUST_TARGET_DIR ${CMAKE_BINARY_DIR}/rust)
        set(RUST_BUILD_ARTIFACT_PATH ${CMAKE_BINARY_DIR}/rust/${RUST_TARGET_TRIPLET}/${RUST_BUILD_TYPE})
        set(RUST_TARGET_TRIPLET_FLAG "--target=${RUST_TARGET_TRIPLET}")
    endif()
endif()

set(ICEORYX2_C_INCLUDE_DIR ${RUST_BUILD_ARTIFACT_PATH}/iceoryx2-ffi-cbindgen/include)

set(ICEORYX2_C_LIB iceoryx2_ffi)
set(ICEORYX2_C_STATIC_LIB_LINK_NAME lib${ICEORYX2_C_LIB}.a)
set(ICEORYX2_C_SHARED_LIB_LINK_NAME lib${ICEORYX2_C_LIB}.so)
if(WIN32 AND MSVC)
    set(ICEORYX2_C_STATIC_LIB_LINK_NAME ${ICEORYX2_C_LIB}.lib)
    set(ICEORYX2_C_SHARED_LIB_LINK_NAME ${ICEORYX2_C_LIB}.dll.lib)
elseif(WIN32 AND NOT MSVC)
    set(ICEORYX2_C_STATIC_LIB_LINK_NAME lib${ICEORYX2_C_LIB}.a)
    set(ICEORYX2_C_SHARED_LIB_LINK_NAME lib${ICEORYX2_C_LIB}.dll.a)
elseif(APPLE)
    # NOTE the libiceoryx2_ffi.dylib generated by has a dependency to the build directory as can be observed
    # with 'otool -L libiceoryx2_ffi.dylib'; we need to find a way to fix this; see also #233
    set(ICEORYX2_C_SHARED_LIB_LINK_NAME lib${ICEORYX2_C_LIB}.dylib)
endif()

set(ICEORYX2_C_STATIC_LIB_LINK_FILE ${RUST_BUILD_ARTIFACT_PATH}/${ICEORYX2_C_STATIC_LIB_LINK_NAME})
set(ICEORYX2_C_SHARED_LIB_LINK_FILE ${RUST_BUILD_ARTIFACT_PATH}/${ICEORYX2_C_SHARED_LIB_LINK_NAME})
set(ICEORYX2_C_SHARED_LIB_DLL_FILE) # intentionally empty; only used on Windows

list(APPEND ICEORYX2_C_LIB_ARTIFACTS ${ICEORYX2_C_STATIC_LIB_LINK_FILE})
list(APPEND ICEORYX2_C_LIB_ARTIFACTS ${ICEORYX2_C_SHARED_LIB_LINK_FILE})
if(WIN32)
    set(ICEORYX2_C_SHARED_LIB_DLL_FILE ${RUST_BUILD_ARTIFACT_PATH}/${ICEORYX2_C_LIB}.dll)
    list(APPEND ICEORYX2_C_LIB_ARTIFACTS ${ICEORYX2_C_SHARED_LIB_DLL_FILE})
endif()

set(RUST_FEATURE_FLAGS "")
list(LENGTH IOX2_RUST_FEATURES IOX2_RUST_FEATURES_COUNT)
if(IOX2_RUST_FEATURES_COUNT GREATER 0)
    list(JOIN IOX2_RUST_FEATURES "," RUST_FEATURE_FLAGS_STRING)
    set(RUST_FEATURE_FLAGS "--features=${RUST_FEATURE_FLAGS_STRING}")
endif()

if(${USE_CARGO})
    # run cargo
    add_custom_target(
        iceoryx2-build-step ALL
        COMMAND cargo build ${RUST_BUILD_TYPE_FLAG} ${RUST_FEATURE_FLAGS} --package iceoryx2-ffi --target-dir=${RUST_TARGET_DIR} ${RUST_TARGET_TRIPLET_FLAG}
        BYPRODUCTS
            ${ICEORYX2_C_INCLUDE_DIR}/iox2/iceoryx2.h
            ${ICEORYX2_C_STATIC_LIB_LINK_FILE}
            ${ICEORYX2_C_SHARED_LIB_LINK_FILE}
            ${ICEORYX2_C_SHARED_LIB_DLL_FILE}
        WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../..
        VERBATIM
        USES_TERMINAL
    )
else()
    add_custom_target(iceoryx2-build-step)
endif()

#
########## C target ##########
#

# include lib

add_library(includes-only INTERFACE)
add_library(iceoryx2-c::includes-only ALIAS includes-only)

add_dependencies(includes-only iceoryx2-build-step)

target_include_directories(includes-only
    INTERFACE
    $<BUILD_INTERFACE:${ICEORYX2_C_INCLUDE_DIR}>
    $<INSTALL_INTERFACE:include/${PREFIX}>
)

# static lib

add_library(static-lib INTERFACE)
add_library(iceoryx2-c::static-lib ALIAS static-lib)

# shared lib

add_library(shared-lib INTERFACE)
add_library(iceoryx2-c::shared-lib ALIAS shared-lib)

# NOTE the solution with specifying a 'BUILD_INTERFACE' and a 'INSTALL_INTERFACE' was the only one that worked;
# alternatively an imported library could be created, e.g. 'iceoryx2_ffi' with a corresponding alias, e.g. 'iceoryx2::ffi';
# the imported lib needs to be present here and also in 'Config.cmake.in' but they need to be named differently, e.g.
# 'iceoryx2_ffi_imported' in 'Config.cmake.in' but with the same alias, e.g 'iceoryx2::ffi';
# the 'target_link_libraries' would then depend on 'iceoryx2::ffi'
include(GNUInstallDirs)
target_link_libraries(static-lib INTERFACE
    iceoryx2-c::includes-only
    $<BUILD_INTERFACE:${ICEORYX2_C_STATIC_LIB_LINK_FILE}>
    $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_LIBDIR}/${ICEORYX2_C_STATIC_LIB_LINK_NAME}>
    $<$<NOT:$<PLATFORM_ID:Windows>>:m pthread>
    $<$<PLATFORM_ID:Windows>:userenv ntdll psapi ws2_32 wsock32>
    $<$<AND:$<PLATFORM_ID:Windows>,$<OR:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>>:bcrypt synchronization>
    $<$<PLATFORM_ID:Darwin>:stdc++>
    $<$<PLATFORM_ID:FreeBSD>:rt util>
)
target_link_libraries(shared-lib INTERFACE
    iceoryx2-c::includes-only
    $<BUILD_INTERFACE:${ICEORYX2_C_SHARED_LIB_LINK_FILE}>
    $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_LIBDIR}/${ICEORYX2_C_SHARED_LIB_LINK_NAME}>
)

include(${CMAKE_CURRENT_LIST_DIR}/cmake/install.cmake)

if(${BUILD_TESTING})
    add_subdirectory(tests)
endif()
